home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / git-4.3 / git-4 / git-4.3.11 / src / gitps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-06  |  20.2 KB  |  980 lines

  1. /* gitps.c -- A process viewer/killer utility.  */
  2.  
  3. /* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /* Written by Tudor Hulubei and Andrei Pitis.  */
  20.  
  21.  
  22. #ifdef HAVE_CONFIG_H
  23. #include <config.h>
  24. #endif
  25.  
  26. #include <stdio.h>
  27.  
  28. #ifdef HAVE_STDLIB_H
  29. #include <stdlib.h>
  30. #else /* !HAVE_STDLIB_H */
  31. #include "ansi_stdlib.h"
  32. #endif /* !HAVE_STDLIB_H */
  33.  
  34. #include <sys/types.h>
  35. #include <ctype.h>
  36. #include <limits.h>
  37. #include "file.h"
  38. #include <fcntl.h>
  39. #include <signal.h>
  40.  
  41. /* SVR2/SVR3.  */
  42. #if !(defined(SIGCHLD)) && defined(SIGCLD)
  43. #define SIGCHLD    SIGCLD
  44. #endif
  45.  
  46. #ifdef HAVE_UNISTD_H
  47. #include <unistd.h>
  48. #endif /* HAVE_UNISTD_H */
  49.  
  50. #include <errno.h>
  51.  
  52. /* Not all systems declare ERRNO in errno.h... and some systems #define it! */
  53. #if !defined (errno)
  54. extern int errno;
  55. #endif /* !errno */
  56.  
  57. #include "stdc.h"
  58. #include "xstring.h"
  59. #include "xmalloc.h"
  60. #include "tty.h"
  61. #include "window.h"
  62. #include "configure.h"
  63. #include "tilde.h"
  64. #include "misc.h"
  65.  
  66.  
  67. int SCREEN_X;
  68. int SCREEN_Y;
  69.  
  70. #define MAX_KEYS        2048
  71. #define MAX_PROCESSES   1024
  72. #define PS_FIELDS         12
  73.  
  74.  
  75. static char *PSFields[PS_FIELDS] =
  76. {
  77.     "TitleForeground",
  78.     "TitleBackground",
  79.     "TitleBrightness",
  80.     "HeaderForeground",
  81.     "HeaderBackground",
  82.     "HeaderBrightness",
  83.     "ScreenForeground",
  84.     "ScreenBackground",
  85.     "ScreenBrightness",
  86.     "StatusForeground",
  87.     "StatusBackground",
  88.     "StatusBrightness"
  89. };
  90.  
  91. #ifdef HAVE_LINUX
  92. static int PSColors[PS_FIELDS] =
  93. {
  94.     CYAN, BLUE, ON, CYAN, RED, ON, BLACK, CYAN, OFF, CYAN, BLUE, ON
  95. };
  96. #else   /* !HAVE_LINUX */
  97. static int PSColors[PS_FIELDS] =
  98. {
  99.     BLACK, WHITE, OFF, WHITE, BLACK, ON, WHITE, BLACK, OFF, BLACK, WHITE, OFF
  100. };
  101. #endif  /* !HAVE_LINUX */
  102.  
  103. #define TitleForeground                 PSColors[0]
  104. #define TitleBackground                 PSColors[1]
  105. #define TitleBrightness                 PSColors[2]
  106. #define HeaderForeground                PSColors[3]
  107. #define HeaderBackground                PSColors[4]
  108. #define HeaderBrightness                PSColors[5]
  109. #define ScreenForeground                PSColors[6]
  110. #define ScreenBackground                PSColors[7]
  111. #define ScreenBrightness                PSColors[8]
  112. #define StatusForeground                PSColors[9]
  113. #define StatusBackground                PSColors[10]
  114. #define StatusBrightness                PSColors[11]
  115.  
  116.  
  117. #ifdef HAVE_LINUX
  118. extern int LinuxConsole;
  119. #endif /* HAVE_LINUX */
  120.  
  121. #ifdef HAVE_LINUX
  122. int AnsiColors = ON;
  123. #else   /* !HAVE_LINUX */
  124. int AnsiColors = OFF;
  125. #endif  /* !HAVE_LINUX */
  126.  
  127.  
  128. char cSection[]  = "[GITPS-Color]";
  129. char bwSection[] = "[GITPS-Monochrome]";
  130. int  processes;
  131. int  PID_index;
  132. int  signal_type = 11;  /* index of SIGTERM in signals table */
  133.  
  134. pid_t pid;
  135. char *home;
  136. char *program;
  137. char *tty_name;
  138. size_t tty_name_len;
  139. char *header_text;
  140. char *TempDirectory;
  141. int UseLastScreenChar;
  142. int StartupScrollStep;
  143. char *stdout_log_name;
  144. char *stderr_log_name;
  145. char *ps_vect[MAX_PROCESSES];
  146. char *screen;
  147. char *global_buf;
  148. int first_on_screen, current_process, scroll_step;
  149. window_t *title_win, *header_win, *screen_win, *status_win;
  150. #ifdef HAVE_GCC
  151. static char title_text[] = " "PRODUCT" "VERSION" - Process Viewer/Killer";
  152. #else
  153. static char title_text[] = " GNU Interactive Tools 4.3.11 - Process Viewer/Killer";
  154. #endif /* !HAVE_GCC */
  155. static char *GitPsModeHelp;
  156. static char no_perm[] = "not owner !";
  157. static char no_proc[] = "no such process ! (REFRESH recommended)";
  158.  
  159.  
  160. struct SIGNAL
  161. {
  162.     char signame[8];
  163.     int  signal;
  164. };
  165.  
  166. static struct SIGNAL signals[] =
  167. {
  168.     { "SIGHUP ", SIGHUP  },
  169.     { "SIGINT ", SIGINT  },
  170.     { "SIGQUIT", SIGQUIT },
  171.     { "SIGILL ", SIGILL  },
  172.     { "SIGFPE ", SIGFPE  },
  173.     { "SIGKILL", SIGKILL },
  174.     { "SIGUSR1", SIGUSR1 },
  175.     { "SIGSEGV", SIGSEGV },
  176.     { "SIGUSR2", SIGUSR2 },
  177.     { "SIGPIPE", SIGPIPE },
  178.     { "SIGALRM", SIGALRM },
  179.     { "SIGTERM", SIGTERM },
  180.     { "SIGCHLD", SIGCHLD },
  181.  
  182. #ifdef SIGSTOP
  183.     { "SIGSTOP", SIGSTOP },
  184. #endif
  185.  
  186. #ifdef SIGTSTP
  187.     { "SIGTSTP", SIGTSTP },
  188. #endif
  189.  
  190. #ifdef SIGCONT
  191.     { "SIGCONT", SIGCONT },
  192. #endif
  193.  
  194.     { "SIGABRT", SIGABRT },
  195.     { "SIGTRAP", SIGTRAP },
  196. };
  197.  
  198.  
  199. #define BUILTIN_OPERATIONS              26
  200.  
  201.  
  202. #define BUILTIN_previous_line            0
  203. #define BUILTIN_next_line                1
  204. #define BUILTIN_scroll_down              2
  205. #define BUILTIN_scroll_up                3
  206. #define BUILTIN_beginning_of_list        4
  207. #define BUILTIN_end_of_list              5
  208. #define BUILTIN_next_signal              6
  209. #define BUILTIN_SIGHUP                   7
  210. #define BUILTIN_SIGINT                   8
  211. #define BUILTIN_SIGQUIT                  9
  212. #define BUILTIN_SIGILL                  10
  213. #define BUILTIN_SIGFPE                  11
  214. #define BUILTIN_SIGKILL                 12
  215. #define BUILTIN_SIGUSR1                 13
  216. #define BUILTIN_SIGSEGV                 14
  217. #define BUILTIN_SIGUSR2                 15
  218. #define BUILTIN_SIGPIPE                 16
  219. #define BUILTIN_SIGALRM                 17
  220. #define BUILTIN_SIGTERM                 18
  221. #define BUILTIN_SIGCHLD                 19
  222. #define BUILTIN_SIGCONT                 20
  223. #define BUILTIN_kill_process            21
  224. #define BUILTIN_refresh                 22
  225. #define BUILTIN_exit                    23
  226. #define BUILTIN_hard_refresh            24
  227.  
  228.  
  229. #define MAX_BUILTIN_NAME                20
  230.  
  231. char built_in[BUILTIN_OPERATIONS][MAX_BUILTIN_NAME] =
  232. {
  233.     "previous-line",
  234.     "next-line",
  235.     "scroll-down",
  236.     "scroll-up",
  237.     "beginning-of-list",
  238.     "end-of-list",
  239.     "next-signal",
  240.     "SIGHUP",
  241.     "SIGINT",
  242.     "SIGQUIT",
  243.     "SIGILL",
  244.     "SIGFPE",
  245.     "SIGKILL",
  246.     "SIGUSR1",
  247.     "SIGSEGV",
  248.     "SIGUSR2",
  249.     "SIGPIPE",
  250.     "SIGALRM",
  251.     "SIGTERM",
  252.     "SIGCHLD",
  253.     "SIGCONT",
  254.     "kill-process",
  255.     "refresh",
  256.     "exit",
  257.     "hard-refresh",
  258. };
  259.  
  260.  
  261. void
  262. remove_log()
  263. {
  264.     if (stdout_log_name) unlink(stdout_log_name);
  265.     if (stderr_log_name) unlink(stderr_log_name);
  266. }
  267.  
  268.  
  269. void
  270. settitle()
  271. {
  272.     memset(global_buf, ' ', SCREEN_X);
  273.     memcpy(global_buf, title_text, strlen(title_text));
  274.  
  275.     tty_colors(TitleBrightness, TitleForeground, TitleBackground);
  276.  
  277.     window_goto(title_win, 0, 0);
  278.     window_puts(global_buf, SCREEN_X);
  279. }
  280.  
  281.  
  282. void
  283. setheader()
  284. {
  285.     memset(global_buf, ' ', SCREEN_X);
  286.     memcpy(global_buf, header_text, strlen(header_text));
  287.  
  288.     tty_colors(HeaderBrightness, HeaderForeground, HeaderBackground);
  289.  
  290.     window_goto(header_win, 0, 0);
  291.     window_puts(global_buf, SCREEN_X);
  292. }
  293.  
  294.  
  295. void
  296. setstatus(what)
  297.    char *what;
  298. {
  299.     memset(global_buf, ' ', SCREEN_X);
  300.  
  301.     if (what)
  302.     memcpy(global_buf, what, strlen(what));
  303.     else
  304.     memcpy(global_buf, GitPsModeHelp, strlen(GitPsModeHelp));
  305.  
  306.     tty_colors(StatusBrightness, StatusForeground, StatusBackground);
  307.  
  308.     window_goto(status_win, 0, 0);
  309.     window_puts(global_buf, SCREEN_X - (sizeof(signals[0].signame) - 1) - 1);
  310. }
  311.  
  312.  
  313. void
  314. setsignal()
  315. {
  316.     int len = sizeof(signals[0].signame) - 1;
  317.  
  318.     tty_colors(StatusBrightness, StatusForeground, StatusBackground);
  319.  
  320.     window_goto(status_win, 0, SCREEN_X - len - 1);
  321.     window_puts(signals[signal_type].signame, len);
  322.     window_putc(' ');
  323. }
  324.  
  325.  
  326. void
  327. free_ps_list()
  328. {
  329.     int i;
  330.  
  331.     for (i = 0; i < MAX_PROCESSES; i++)
  332.     if (ps_vect[i])
  333.     {
  334.         xfree(ps_vect[i]);
  335.         ps_vect[i] = NULL;
  336.     }
  337. }
  338.  
  339.  
  340. char *
  341. read_ps_line(ps_output, line)
  342.     FILE *ps_output;
  343.     char *line;
  344. {
  345.     int c;
  346.     char *ok;
  347.     size_t lastchar;
  348.  
  349.     ok = fgets(line, SCREEN_X + 1, ps_output);
  350.  
  351.     if (line[lastchar = strlen(line) - 1] == '\n')
  352.     line[lastchar] = 0;
  353.     else
  354.     while ((c = fgetc(ps_output)) != '\n' && c != EOF);
  355.  
  356.     return ok;
  357. }
  358.  
  359.  
  360. int
  361. get_PID_index(ps_output)
  362.     FILE *ps_output;
  363. {
  364.     int i;
  365.     char *h = header_text;
  366.  
  367.     if (read_ps_line(ps_output, header_text) == NULL)
  368.     return -1;
  369.  
  370.     if (strstr(header_text, "PID") == NULL)
  371.     return -1;
  372.  
  373.     for (i = 0; ; i++)
  374.     {
  375.     while (isspace(*h))
  376.         h++;
  377.  
  378.     if (memcmp(h, "PID", 3) == 0)
  379.         return i;
  380.  
  381.     while (!isspace(*h))
  382.         h++;
  383.     }
  384. }
  385.  
  386.  
  387. int
  388. kill_process(process_index)
  389.     int process_index;
  390. {
  391.     int i;
  392.     char pidstr[32];
  393.     char *p = ps_vect[process_index];
  394.  
  395.     if (p == NULL)
  396.     return 0;
  397.  
  398.     for (i = 0; i < PID_index; i++)
  399.     {
  400.     while (isspace(*p)) p++;
  401.     if (memcmp(p, "PID", 3) == 0) return i;
  402.     while (!isspace(*p)) p++;
  403.     }
  404.  
  405.     i = 0;
  406.     while (isspace(*p)) p++;
  407.     while (!isspace(*p)) pidstr[i++] = *p++;
  408.     pidstr[i] = 0;
  409.     return !kill(atoi(pidstr), signals[signal_type].signal);
  410. }
  411.  
  412.  
  413. void
  414. build_ps_list(ps_output)
  415.     FILE *ps_output;
  416. {
  417.     int i = 0;
  418.  
  419.     do
  420.     ps_vect[i] = xmalloc(SCREEN_X + 1);
  421.     while (read_ps_line(ps_output, ps_vect[i++]));
  422.  
  423.     xfree(ps_vect[--i]);
  424.     ps_vect[i] = NULL;
  425.     processes = i;
  426. }
  427.  
  428.  
  429. void
  430. update_process(process, update_color)
  431.     int process, update_color;
  432. {
  433.     memset(global_buf, ' ', SCREEN_X);
  434.     memcpy(global_buf, ps_vect[process], strlen(ps_vect[process]));
  435.  
  436.     if (update_color)
  437.     {
  438.     tty_brightness(ScreenBrightness);
  439.  
  440.     if (process == current_process)
  441.     {
  442.         tty_foreground(ScreenBackground);
  443.         tty_background(ScreenForeground);
  444.     }
  445.     else
  446.     {
  447.         tty_foreground(ScreenForeground);
  448.         tty_background(ScreenBackground);
  449.     }
  450.     }
  451.  
  452.     window_goto(screen_win, process - first_on_screen, 0);
  453.     window_puts(global_buf, SCREEN_X);
  454. }
  455.  
  456.  
  457. void
  458. update_all()
  459. {
  460.     int i;
  461.  
  462.     tty_colors(ScreenBrightness, ScreenForeground, ScreenBackground);
  463.  
  464.     window_goto(screen_win, 0, 0);
  465.  
  466.     for (i = first_on_screen;
  467.      i < processes && (i - first_on_screen < SCREEN_Y - 3); i++)
  468.         if (i != current_process)
  469.         update_process(i, OFF);
  470.         else
  471.         window_goto(screen_win, i - first_on_screen, 0);
  472.  
  473.     update_process(current_process, ON);
  474.  
  475.     tty_colors(ScreenBrightness, ScreenForeground, ScreenBackground);
  476.  
  477.     memset(global_buf, ' ', SCREEN_X);
  478.  
  479.     for (; i - first_on_screen < SCREEN_Y - 3; i++)
  480.     {
  481.     window_goto(screen_win, i - first_on_screen, 0);
  482.     window_puts(global_buf, SCREEN_X);
  483.     }
  484.  
  485.     window_goto(screen_win, current_process-first_on_screen, SCREEN_X-1);
  486. }
  487.  
  488.  
  489. void
  490. clean_up()
  491. {
  492.     tty_exit(NULL);
  493.     remove_log();
  494. }
  495.  
  496.  
  497. void
  498. fatal(postmsg)
  499.     char *postmsg;
  500. {
  501.     clean_up();
  502.     fprintf(stderr, "%s: fatal error: %s.\n", program, postmsg);
  503.     exit(1);
  504. }
  505.  
  506.  
  507. int
  508. ps(args)
  509.     char *args;
  510. {
  511.     char *ps_cmd;
  512.     FILE *stdout_log, *stderr_log;
  513.  
  514.     /* See the comment in system.c on closing tty descriptors.  */
  515.  
  516.     int old_stdout = dup(1);
  517.     int old_stderr = dup(2);
  518.  
  519.     close(1);
  520.     close(2);
  521.  
  522.     stdout_log = fopen(stdout_log_name, "w");
  523.     stderr_log = fopen(stderr_log_name, "w");
  524.  
  525.     ps_cmd = xmalloc(16 + (args ? strlen(args) : 0) + 1);
  526.  
  527.     if (args)
  528.     sprintf(ps_cmd, "ps %s", args);
  529.     else
  530.     sprintf(ps_cmd, "ps");
  531.  
  532.     if (system(ps_cmd) != 0)
  533.     {
  534.     fclose(stdout_log);
  535.     fclose(stderr_log);
  536.  
  537.     dup(old_stdout);
  538.     dup(old_stderr);
  539.  
  540.     close(old_stdout);
  541.     close(old_stderr);
  542.  
  543.     fprintf(stderr, "%s: invalid command line.\n", program);
  544.     return 0;
  545.     }
  546.  
  547.     xfree(ps_cmd);
  548.  
  549.     fclose(stdout_log);
  550.     fclose(stderr_log);
  551.  
  552.     dup(old_stdout);
  553.     dup(old_stderr);
  554.  
  555.     close(old_stdout);
  556.     close(old_stderr);
  557.  
  558.     return 1;
  559. }
  560.  
  561.  
  562. RETSIGTYPE
  563. panic(signum)
  564.     int signum;
  565. {
  566.     fatal_signal(signum);
  567. }
  568.  
  569.  
  570. int
  571. read_keys(keys)
  572.     int keys;
  573. {
  574.     char *contents;
  575.     char key_seq[80];
  576.     int i, j, need_convertion;
  577.  
  578.  
  579.     for (i = keys; i < MAX_KEYS; i++)
  580.     {
  581.     configuration_getvarinfo(key_seq, &contents, 1, NO_SEEK);
  582.  
  583.     if (*key_seq == 0)
  584.         break;
  585.  
  586.     if (*key_seq != '^')
  587.     {
  588.         char *key_seq_ptr = tty_get_symbol_key_seq(key_seq);
  589.  
  590.         if (!(need_convertion = key_seq_ptr == NULL))
  591.         strcpy(key_seq, key_seq_ptr);
  592.     }
  593.     else
  594.         need_convertion = 1;
  595.  
  596.     if (contents == NULL)
  597.         continue;
  598.  
  599.     for (j = 0; j < BUILTIN_OPERATIONS; j++)
  600.         if (strcmp(contents, built_in[j]) == 0)
  601.         break;
  602.  
  603.     if (j < BUILTIN_OPERATIONS)
  604.     {
  605.         if (!need_convertion || tty_key_convert((unsigned char *)key_seq))
  606.         tty_key_list_insert((unsigned char *)key_seq, (void *)j);
  607.     }
  608.     else
  609.         fprintf(stderr, "%s: invalid built-in operation: %s.\n",
  610.             program, contents);
  611.     }
  612.  
  613.     return i;
  614. }
  615.  
  616.  
  617. int
  618. main(argc, argv)
  619.     int argc;
  620.     char *argv[];
  621. {
  622.     int key, keys;
  623.     tty_key_t *ks;
  624.     FILE *stdout_log;
  625.     int repeat_count;
  626.     char *tmp, *data = NULL;
  627.     int need_update, need_update_all, old_current_process;
  628.  
  629.  
  630.     program = argv[0];
  631.     pid     = getpid();
  632.  
  633.     home = getenv("HOME");
  634.     if (home == NULL)
  635.     home = ".";
  636.  
  637.     get_tty_name();
  638.     get_login_name();
  639.  
  640.     tty_get_capabilities();
  641.     tty_kbdinit(TTY_FULL_INPUT);
  642.  
  643.     signal(SIGTERM, panic);
  644.     signal(SIGINT , panic);
  645.     signal(SIGQUIT, panic);
  646.     signal(SIGSEGV, panic);
  647.     signal(SIGHUP,  panic);
  648.  
  649.     signal(SIGILL,  SIG_IGN);
  650.     signal(SIGTRAP, SIG_IGN);
  651.     signal(SIGABRT, SIG_IGN);
  652.     signal(SIGUSR1, SIG_IGN);
  653.     signal(SIGUSR2, SIG_IGN);
  654.  
  655. #ifdef SIGTSTP
  656.     signal(SIGTSTP, SIG_IGN);
  657. #endif
  658.  
  659. #ifdef SIGCONT
  660.     signal(SIGCONT, SIG_IGN);
  661. #endif
  662.  
  663.     signal(SIGALRM, SIG_IGN);
  664.     signal(SIGPIPE, SIG_IGN);
  665.     signal(SIGFPE,  SIG_IGN);
  666.  
  667.     common_configuration_init();
  668.     use_section("[GITPS-Keys]");
  669.     keys = read_keys(0);
  670.     configuration_end();
  671.  
  672.     specific_configuration_init();
  673.  
  674.     tty_get_size(&SCREEN_X, &SCREEN_Y);
  675.     tty_startup(UseLastScreenChar);
  676.  
  677.  
  678.     use_section("[Setup]");
  679.  
  680.     configuration_getvarinfo("TempDirectory", &data, 1, DO_SEEK);
  681.     TempDirectory = data ? tilde_expand(data) : "/tmp";
  682.  
  683.     AnsiColors         = get_flag_var("AnsiColors", OFF);
  684.     UseLastScreenChar  = get_flag_var("UseLastScreenChar", OFF);
  685.     StartupScrollStep  = get_int_var("StartupScrollStep", (SCREEN_Y - 3) / 2);
  686.  
  687.     if (StartupScrollStep <= 0 || StartupScrollStep >= (SCREEN_Y - 3) - 1)
  688.     StartupScrollStep = (SCREEN_Y - 3) / 2;
  689.  
  690.     scroll_step = StartupScrollStep;
  691.  
  692.  
  693.     use_section("[GITPS-Setup]");
  694.  
  695.     GitPsModeHelp = get_string_var("GitPsModeHelp", "");
  696.  
  697.  
  698.     use_section(AnsiColors ? cSection : bwSection);
  699.  
  700.     get_colorset_var(PSColors, PSFields, PS_FIELDS);
  701.  
  702.  
  703.     use_section("[GITPS-Keys]");
  704.  
  705.     keys = read_keys(keys);
  706.  
  707.     if (keys == MAX_KEYS)
  708.     fprintf(stderr, "%s: too many key sequences; only %d are allowed.\n",
  709.         program, MAX_KEYS);
  710.  
  711.     configuration_end();
  712.  
  713. #ifndef HAVE_LONG_FILE_NAMES
  714.     fprintf(stderr, "%s: warning: your system doesn't support long file names.",
  715.         program);
  716. #endif /* !HAVE_LONG_FILE_NAMES */
  717.  
  718. #ifdef HAVE_LINUX
  719.     if (LinuxConsole)
  720.     screen = xmalloc(4 + SCREEN_X * SCREEN_Y * 2);
  721. #endif  /* HAVE_LINUX */
  722.  
  723.     stdout_log_name = xmalloc(32 + strlen(TempDirectory) + 1);
  724.     stderr_log_name = xmalloc(32 + strlen(TempDirectory) + 1);
  725.     sprintf(stdout_log_name, "%s/gitps.1.%d", TempDirectory, (int)pid);
  726.     sprintf(stderr_log_name, "%s/gitps.2.%d", TempDirectory, (int)pid);
  727.  
  728.     global_buf  = xmalloc(SCREEN_X + 1);
  729.  
  730.     header_text = xmalloc(SCREEN_X + 1);
  731.  
  732.     title_win  = window_init(0, 0,            1,            SCREEN_X);
  733.     header_win = window_init(0, 1,            1,            SCREEN_X);
  734.     screen_win = window_init(0, 2,            SCREEN_Y - 3, SCREEN_X);
  735.     status_win = window_init(0, SCREEN_Y - 1, 1,            SCREEN_X);
  736.  
  737.     tty_get_screen(screen);
  738.     tty_set_mode(TTY_NONCANONIC);
  739.     tty_defaults();
  740.  
  741.     first_on_screen = current_process = 0;
  742.  
  743. restart:
  744.  
  745.     if (ps(argc > 1 ? argv[1] : NULL) == 0)
  746.     {
  747.     remove_log();
  748.     goto end;
  749.     }
  750.  
  751.     stdout_log = fopen(stdout_log_name, "r");
  752.     remove_log();
  753.  
  754.     if ((PID_index = get_PID_index(stdout_log)) == -1)
  755.     goto end;
  756.  
  757.     free_ps_list();
  758.     build_ps_list(stdout_log);
  759.     fclose(stdout_log);
  760.  
  761.     settitle();
  762.     setstatus(NULL);
  763.     setsignal();
  764.     setheader();
  765.  
  766.     current_process = min(current_process, processes - 1);
  767.  
  768.     update_all();
  769.  
  770.     while (1)
  771.     {
  772.     ks  = tty_get_key(&repeat_count);
  773.     key = (int)ks->aux_data;
  774.  
  775.     switch (key)
  776.     {
  777.         case BUILTIN_previous_line:
  778.  
  779.         need_update_all = need_update = 0;
  780.  
  781.         while (repeat_count--)
  782.         {
  783.             if (current_process != 0)
  784.             current_process--;
  785.             else
  786.             break;
  787.  
  788.             if (current_process + 1 == first_on_screen)
  789.             {
  790.             first_on_screen = max(0, first_on_screen -
  791.                           scroll_step);
  792.             need_update_all = 1;
  793.             }
  794.             else
  795.             {
  796.             if (!need_update)
  797.                 update_process(current_process + 1, ON);
  798.  
  799.             need_update = 1;
  800.             }
  801.         }
  802.  
  803.         if (need_update_all)
  804.             update_all();
  805.         else
  806.             if (need_update)
  807.             update_process(current_process, ON);
  808.         break;
  809.  
  810.         case BUILTIN_next_line:
  811.  
  812.         need_update_all = need_update = 0;
  813.  
  814.         while (repeat_count--)
  815.         {
  816.             if (current_process < processes - 1)
  817.             current_process++;
  818.             else
  819.             break;
  820.  
  821.             if (current_process - first_on_screen >= SCREEN_Y - 3)
  822.             {
  823.             first_on_screen = min(first_on_screen +
  824.                           scroll_step,
  825.                           processes - 1 -
  826.                           (SCREEN_Y - 3) + 1);
  827.             need_update_all = 1;
  828.             continue;
  829.             }
  830.  
  831.             if (!need_update)
  832.             update_process(current_process - 1, ON);
  833.  
  834.             need_update = 1;
  835.         }
  836.  
  837.         if (need_update_all)
  838.             update_all();
  839.         else
  840.             if (need_update)
  841.             update_process(current_process, ON);
  842.         break;
  843.  
  844.         case BUILTIN_scroll_down:
  845.  
  846.         if (current_process == 0)
  847.             break;
  848.  
  849.         old_current_process = current_process;
  850.  
  851.         if (current_process < SCREEN_Y - 3)
  852.             current_process = first_on_screen = 0;
  853.         else
  854.         {
  855.             current_process -= SCREEN_Y - 3;
  856.             first_on_screen = max(0, first_on_screen - (SCREEN_Y - 3));
  857.         }
  858.  
  859.         if (processes > SCREEN_Y - 3)
  860.             update_all();
  861.         else
  862.         {
  863.             update_process(old_current_process, ON);
  864.             update_process(current_process, ON);
  865.         }
  866.  
  867.         break;
  868.  
  869.         case BUILTIN_scroll_up:
  870.  
  871.         if (current_process == processes - 1)
  872.             break;
  873.  
  874.         old_current_process = current_process;
  875.  
  876.         if (processes - 1 - first_on_screen < SCREEN_Y - 3)
  877.             current_process = processes - 1;
  878.         else
  879.             if (processes - 1 - current_process < SCREEN_Y - 3)
  880.             {
  881.             current_process = processes - 1;
  882.             first_on_screen = processes - 1 - (SCREEN_Y - 3) + 1;
  883.             }
  884.             else
  885.             {
  886.             current_process += SCREEN_Y - 3;
  887.             first_on_screen = min(first_on_screen + SCREEN_Y - 3,
  888.                           (processes - 1) -
  889.                           (SCREEN_Y - 3) + 1);
  890.             }
  891.  
  892.         if (processes > SCREEN_Y - 3)
  893.             update_all();
  894.         else
  895.         {
  896.             update_process(old_current_process, ON);
  897.             update_process(current_process, ON);
  898.         }
  899.  
  900.         break;
  901.  
  902.         case BUILTIN_beginning_of_list:
  903.  
  904.         if (current_process == 0)
  905.             break;
  906.  
  907.         current_process = first_on_screen = 0;
  908.         update_all();
  909.         break;
  910.  
  911.         case BUILTIN_end_of_list:
  912.  
  913.         if (current_process == processes - 1)
  914.             break;
  915.  
  916.         current_process = processes - 1;
  917.         first_on_screen = max(0, (processes - 1) - (SCREEN_Y - 3) + 1);
  918.         update_all();
  919.         break;
  920.  
  921.         case BUILTIN_next_signal:
  922.  
  923.         signal_type++;
  924.         signal_type %= sizeof(signals) / sizeof(struct SIGNAL);
  925.         setsignal();
  926.         break;
  927.  
  928.         case BUILTIN_SIGHUP : signal_type =  0; setsignal(); break;
  929.         case BUILTIN_SIGINT : signal_type =  1; setsignal(); break;
  930.         case BUILTIN_SIGQUIT: signal_type =  2; setsignal(); break;
  931.         case BUILTIN_SIGILL : signal_type =  3; setsignal(); break;
  932.         case BUILTIN_SIGFPE : signal_type =  4; setsignal(); break;
  933.         case BUILTIN_SIGKILL: signal_type =  5; setsignal(); break;
  934.         case BUILTIN_SIGUSR1: signal_type =  6; setsignal(); break;
  935.         case BUILTIN_SIGSEGV: signal_type =  7; setsignal(); break;
  936.         case BUILTIN_SIGUSR2: signal_type =  8; setsignal(); break;
  937.         case BUILTIN_SIGPIPE: signal_type =  9; setsignal(); break;
  938.         case BUILTIN_SIGALRM: signal_type = 10; setsignal(); break;
  939.         case BUILTIN_SIGTERM: signal_type = 11; setsignal(); break;
  940.         case BUILTIN_SIGCHLD: signal_type = 12; setsignal(); break;
  941.         case BUILTIN_SIGCONT: signal_type = 13; setsignal(); break;
  942.  
  943.         case BUILTIN_hard_refresh:
  944.  
  945.         tty_touch();
  946.  
  947.         case BUILTIN_refresh:
  948.  
  949.         goto restart;
  950.  
  951.         case BUILTIN_exit:
  952.  
  953.         goto end;
  954.  
  955.         case BUILTIN_kill_process:
  956.  
  957.         if (!kill_process(current_process))
  958.         {
  959.             tty_beep();
  960.             memset(global_buf, ' ', SCREEN_X);
  961.             tmp = xmalloc(16 + strlen((errno==EPERM)?no_perm:no_proc));
  962.             sprintf(tmp, "Error: %s", (errno==EPERM)?no_perm:no_proc);
  963.             setstatus(tmp);
  964.             xfree(tmp);
  965.             errno = 0;
  966.             tty_get_key(NULL);
  967.             setstatus(NULL);
  968.             setsignal();
  969.         }
  970.         break;
  971.     }
  972.     }
  973.  
  974.   end:
  975.  
  976.     remove_log();
  977.     tty_exit(screen);
  978.     return 0;
  979. }
  980.